package top.wardyan.sqlchecker.util;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.ICallback;
import com.jfinal.plugin.activerecord.Record;

import top.wardyan.base.common.db.dialect.SQLBuilderFactory;
import top.wardyan.base.common.db.kits.DbTypeKit;
import top.wardyan.base.common.db.po.ResultSetUtil;
import top.wardyan.base.common.db.po.WRecord;

/**
 * 取代DbUtil, 执行SQL语句的查询操作. 存储过程的执行交给专用工具, 这里只负责SQL语句的查询操作
 * @author harrydeep@wardyan.top
 * 2022年7月5日
 * 2022-07-30: 方法名大写开头的,是根据参数名赋值;方法名小写开够的,是根据占位符?赋值
 */
public class DbQryKit {
	
	
	
//	/**
//	 * 执行查询
//	 * @param configName
//	 * @param procname
//	 * @param fetchSize
//	 * @param params
//	 * @return
//	 */
//	public static WRecord qry(String configName, String sql, int fetchSize, Object...params) {
//		return (WRecord) Db.use(configName).execute(new ICallback(){
//			@Override
//			public WRecord call(Connection conn) throws SQLException {
//				java.sql.CallableStatement proc = conn.prepareCall(procname);
//				if(params != null && params.length > 0) {
//					for(int i = 0, size = params.length; i < size; i++) {
//						proc.setObject(i + 1, params[i]);
//					}
//				}
//				proc.setQueryTimeout(OUTOFTIME);	// 默认180s超时
//				
//				//var ok = proc.getParameterMetaData();
//				
//				try {
//					var r = proc.executeQuery();
//					if(fetchSize > 0) {
//						r.setFetchSize(fetchSize);
//					}
//					return ResultSetUtil.fetch(r);
//				} catch (SQLException e) {
//					throw e;
//				}
//			}
//		});
//	}
	
	/** 最新 最全的执行.
	 *  2022-04-03 返回结果有可能是null
	 *  注意, 这里要求必须有返回数据集!  
	 **/
	public static WRecord Qry(String configName, String sql, Integer fetchSize, Integer outtime, Object...params) {
		return (WRecord) Db.use(configName).execute(new ICallback(){
			@Override
			public WRecord call(Connection conn) throws SQLException {
				java.sql.CallableStatement proc = conn.prepareCall(sql);
				WRecord rs = null;
				if(params != null && params.length > 0) {
					for(int i = 0, size = params.length; i < size; i++) {
						proc.setObject(i + 1, params[i]);
					}
				}
				if(outtime > 0) {
					proc.setQueryTimeout(outtime);
				}
				try {
					var r = proc.executeQuery();
					if(fetchSize > 0) {
						r.setFetchSize(fetchSize);
					}
					rs = ResultSetUtil.fetch(r);
				} catch (SQLException e) {
					throw e;
				}
				return rs;
			}
		});
	}
	

	/**
	 * 2022-07-07 根据SQL去查询, sql语句不能是表名
	 * @param configName
	 * @param sql
	 * @param params
	 * @return
	 */
	public static WRecord qry(String configName, String sql, Object...params) {
		return Qry(configName, sql, 0, 0, params);
	}

	/**
	 * 全等操作. 注意这是在外面套了一层
	 * @param configName
	 * @param sql 也可以是表名
	 * @param params
	 * @return
	 */
	public static WRecord qry(String configName, String sql, Record params) {
		
		StringBuilder str = new StringBuilder("SELECT * FROM ");
		
		// sql里有空格说明是语句, 没有空格说明是表名
		if(sql.contains(" ")) {
			str.append(" ( ").append(sql).append(" ) ");
		}else {
			str.append(sql);
		}
		
		str.append(" AS __a__");
		
		List<Object> ps = new LinkedList<Object>();		// params.getColumns().size() * 2 + 1
		
		if(params != null && params.getColumns().size() > 0) {
			str.append(" WHERE ");
			
			
			String[] cnames = params.getColumnNames();
			int i = 1;
			for(var n : cnames) {
				str.append("__a__.").append(n).append("=?").append(i < cnames.length ? " AND " : "");
				i++;
				ps.add(params.getObject(n));
			}
		}
		
		return qry(configName, str.toString(), ps.toArray());
	}
	
	
	
	/**
	 * 包括操作符的
	 */
	
	
	
	
	/**
	 * 执行查询语句, 根据主键
	 * @param configName	配置名
	 * @param tableName		表名
	 * @param primaryKeys	主键
	 * @param params		查询参数
	 * @param fields		要返回哪些列
	 * @return
	 */
	public static WRecord find(String configName, String tableName, String[] primaryKeys, Record params, String[] fields) {
		var dbtype = DbTypeKit.dbtype(configName);		// 数据库类型
		var builder = SQLBuilderFactory.getInstance(dbtype);	// SQL生成器
		String sql = builder.findByPrimaryKey(tableName, primaryKeys, fields);
		
		List<Object> ps = new LinkedList<>();
		if(primaryKeys.length == 1) {	// 只有一个主键字段
			ps.add(params.get(primaryKeys[0]));
		}else {
			for(var p : primaryKeys) {
				ps.add(params.get(p));
			}
		}
		
		return qry(configName, sql, ps.toArray());
	}

	/**
	 * 2022-07-07 根据主键执行SQL语句查询
	 * @param configName
	 * @param tableName
	 * @param primaryKeys
	 * @param params
	 * @return
	 */
	public static WRecord find(String configName, String tableName, String[] primaryKeys, Record params) {
		return find(configName, tableName, primaryKeys, params, null);
	}
	

	/**
	 * 2022-07-07 根据主键执行SQL语句查询
	 * @param configName
	 * @param tableName
	 * @param primaryKeys
	 * @param params
	 * @param fields 要返回那些列
	 * @return
	 */
	public static WRecord find(String configName, String tableName, String primaryKeys, Record params, String[] fields) {
		return find(configName, tableName, new String[] {primaryKeys}, params, fields);
	}
	

	
	/**
	 * 2022-07-07 根据主键执行SQL语句查询
	 * @param configName
	 * @param tableName
	 * @param primaryKeys
	 * @param params
	 * @return
	 */
	public static WRecord find(String configName, String tableName, String primaryKeys, Record params) {
		return find(configName, tableName, primaryKeys, params, null);
	}
	

	/**
	 * 2022-07-07 根据sID进行查询,必须是主表才行
	 * @param configName
	 * @param tableName
	 * @param sID
	 * @return
	 */
	public static WRecord find(String configName, String tableName, Integer sID) {
		return find(configName, tableName, "sID", new Record().set("sID", sID));
	}

	/**
	 * 2022-07-07 根据mID和dID进行查询.必须是明细表才行
	 * @param configName
	 * @param tableName
	 * @param mID
	 * @param dID
	 * @return
	 */
	public static WRecord find(String configName, String tableName, Integer mID, Integer dID) {
		return find(configName, tableName, "sID", new Record().set("mID", mID).set("dID", dID));
	}
	
	/**
	 * 明细表,根据mID查询列表
	 * @param configName
	 * @param tableName
	 * @param mID
	 * @return
	 */
	public static WRecord qry(String configName, String tableName, Integer mID) {
		return qry(configName, tableName, new Record().set("mID", mID));
	}
	
	
	
	
	
	
	
	
	
	
	
	
	

}
